package vip.xiaonuo.tasks;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.client.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import vip.xiaonuo.core.timer.TimerTaskRunner;
import vip.xiaonuo.facedoor.modular.device.entity.DeviceCategory;
import vip.xiaonuo.facedoor.modular.devicebase.entity.DeviceBase;
import vip.xiaonuo.facedoor.modular.devicebase.service.DeviceBaseService;
import vip.xiaonuo.facedoor.modular.memberdevice.constant.MemberDeviceConstant;
import vip.xiaonuo.facedoor.modular.memberdevice.entity.MemberDevice;
import vip.xiaonuo.facedoor.modular.memberdevice.service.MemberDeviceService;
import vip.xiaonuo.facedoor.modular.visitordevice.entity.VisitorDevice;
import vip.xiaonuo.facedoor.modular.visitordevice.service.VisitorDeviceService;
import vip.xiaonuo.sys.modular.timer.entity.SysTimers;
import vip.xiaonuo.sys.modular.timer.enums.TimerJobStatusEnum;
import vip.xiaonuo.sys.modular.timer.service.SysTimersService;
import vip.xiaonuo.sys.modular.timer.service.TimerExeService;
import vip.xiaonuo.sys.modular.timer.util.TaskUtil;
import vip.xiaonuo.tasks.service.MemberIssuedService;
import vip.xiaonuo.tasks.service.VisitorIssuedService;
import vip.xiaonuo.tasks.synchronize.LockQueue;

import java.util.Date;
import java.util.List;


@Component
@Slf4j
public class IssuedTask implements TimerTaskRunner, ApplicationRunner {

    @Autowired
    private MemberIssuedService memberIssuedService;

    @Autowired
    private VisitorIssuedService visitorIssuedService;

    @Autowired
    private TimerExeService timerExeService;

    @Autowired
    private SysTimersService sysTimersService;

    @Autowired
    private MemberDeviceService memberDeviceService;

    @Autowired
    private DeviceBaseService deviceBaseService;

    @Autowired
    private VisitorDeviceService visitorDeviceService;

    @Override
    public void action(String param, String taskId) {
        facedoorTaskIssu(param, taskId);
    }

    @Override
    @XxlJob("issuedTask")
    public void executeXxlJob() throws InterruptedException {
        String jobParam = XxlJobHelper.getJobParam();
        try {
            long currentTimeMillis = System.currentTimeMillis();
            // taskIds
            String[] split = jobParam.split(",");

            for (String deviceSn : split) {
                DeviceBase deviceBase = deviceBaseService.getOne(new LambdaQueryWrapper<DeviceBase>().eq(DeviceBase::getRegistrationCode, deviceSn));
                if (deviceBase == null) {
                    log.error("找不到设备【{}】", deviceBase);
                    continue;
                }
                if (deviceBase.getDeviceSyncStatus() == null) {
                    log.error("设备【{}】未选择用户组", deviceBase.getName());
                    return;
                }
                if (ObjectUtil.equal(deviceBase.getDeviceSyncStatus(), 2)) {
                    log.error("设备【{}】人员信息发生变更中，本次任务跳过执行!", deviceBase.getName());
                    return;
                }
                if (!ObjectUtil.equal(deviceBase.getDeviceState(), "1")) {
                    log.error("设备【{}】断线不进行人员下发!", deviceBase.getName());
                    return;
                }
                log.info("设备【{}】开始下发人员", deviceBase.getName());

                try {
                    // 人员下发
                    memberIssue(currentTimeMillis, deviceBase.getId());
                } catch (Exception e) {
                    log.error("下发人员发生错误【{}】", ExceptionUtils.getMessage(e));
                }
                try {
                    // 访客下发
                    visitorIssue(deviceBase.getId());
                } catch (Exception e) {
                    log.error("下发访客发生错误【{}】", ExceptionUtils.getMessage(e));
                }
            }
            log.info("==【{}】==总体耗时==================================================【{}】", jobParam, (System.currentTimeMillis() - currentTimeMillis));

        } catch (Exception e) {
            log.error("taskParam【{}】执行发生错误【{}】", jobParam, ExceptionUtils.getMessage(e));
        }
    }


    private void facedoorTaskIssu(String taskPrams, String taskID) {
        try {
            synchronized (IssuedTask.class) {
                if (LockQueue.currentExecuteTask.contains(taskPrams)) {
                    log.info("当前任务【{}】正在执行请稍后！", taskPrams);
                    return;
                }
                log.info("【{}】taskID加入任务执行队列", taskPrams);
                LockQueue.currentExecuteTask.add(taskPrams);
            }
            long currentTimeMillis = System.currentTimeMillis();
            // taskId为当前deviceId
            Long deviceId = Long.parseLong(taskPrams);

            DeviceBase byId = deviceBaseService.getById(deviceId);
            if (byId == null) {
                log.error("找不到设备【{}】", byId);
                log.info("【{}】taskID剔除任务执行队列", taskPrams);
                timerExeService.stopTimer(taskPrams);
                LockQueue.currentExecuteTask.remove(taskID);
                return;
            }

            if (byId.getDeviceSyncStatus() == null) {
                log.error("设备【{}】未选择用户组", byId.getName());
                log.info("【{}】taskID剔除任务执行队列", taskPrams);
                LockQueue.currentExecuteTask.remove(taskPrams);
                return;
            }

            if (ObjectUtil.equal(byId.getDeviceSyncStatus(), 2)) {
                log.error("设备【{}】人员信息发生变更中，本次任务跳过执行!", byId.getName());
                log.info("【{}】taskID剔除任务执行队列", taskPrams);
                LockQueue.currentExecuteTask.remove(taskPrams);
                return;
            }

            log.info("设备【{}】开始下发人员", byId.getName());
            try {
                // 人员下发
                memberIssue(currentTimeMillis, deviceId);
            } catch (Exception e) {
                log.error("下发人员发生错误【{}】", ExceptionUtils.getMessage(e));
                log.info("【{}】taskID剔除任务执行队列", taskPrams);
                LockQueue.currentExecuteTask.remove(taskPrams);
            }

            try {
                // 访客下发
                visitorIssue(deviceId);
            } catch (Exception e) {
                log.error("下发访客发生错误【{}】", ExceptionUtils.getMessage(e));
                log.info("【{}】taskID剔除任务执行队列", taskPrams);
                LockQueue.currentExecuteTask.remove(taskPrams);
            }

            log.info("==【{}】==总体耗时==================================================【{}】", byId.getName(), (System.currentTimeMillis() - currentTimeMillis));
        } catch (Exception e) {
            log.error("taskPrams【{}】执行发生错误【{}】", taskPrams, ExceptionUtils.getMessage(e));
            log.info("【{}】taskID剔除任务执行队列", taskPrams);
            LockQueue.currentExecuteTask.remove(taskPrams);
        }
        LockQueue.currentExecuteTask.remove(taskPrams);
    }

    private synchronized void visitorIssue(Long deviceId) {
        long visitorMillis = System.currentTimeMillis();
        List<VisitorDevice> visitorDevices = visitorDeviceService.list(new LambdaQueryWrapper<VisitorDevice>().eq(VisitorDevice::getDeviceId, deviceId)
                .in(VisitorDevice::getStatus, MemberDeviceConstant.ADD, MemberDeviceConstant.DELETE, MemberDeviceConstant.UPDATE));

        if (CollectionUtils.isEmpty(visitorDevices)) {
            log.info("deviceId【{}】不存在需要下发的访客!", deviceId);
            return;
        }

        log.info("【{}】访客下发开始时间======================================================【{}】", deviceId, DateUtils.formatDate(new Date()));
        visitorIssuedService.issued(deviceId, visitorDevices);
        log.info("【{}】====访客下发耗时==================================================【{}】", deviceId, (System.currentTimeMillis() - visitorMillis));
    }

    private synchronized void memberIssue(long currentTimeMillis, Long deviceId) {
        // 人员下发
        List<MemberDevice> memberDevices = memberDeviceService.list(new LambdaQueryWrapper<MemberDevice>().eq(MemberDevice::getDeviceId, deviceId).in(MemberDevice::getStatus, MemberDeviceConstant.ADD, MemberDeviceConstant.DELETE, MemberDeviceConstant.UPDATE));

        if (CollectionUtils.isEmpty(memberDevices)) {
            log.info("deviceId【{}】不存在需要下发的人员!", deviceId);
            return;
        }
        log.info("【{}】人员下发开始时间======================================================【{}】", deviceId, DateUtils.formatDate(new Date()));
        memberIssuedService.issued(deviceId, memberDevices);
        log.info("【{}】====人员下发耗时==================================================【{}】", deviceId, (System.currentTimeMillis() - currentTimeMillis));
    }

    @Override
    public void run(ApplicationArguments args) {
        if (TaskUtil.executeXxlJob()) {
            return;
        }
        List<DeviceBase> deviceBases = deviceBaseService.list();
        for (DeviceBase deviceBase : deviceBases) {
            List<SysTimers> timers = sysTimersService.list(new LambdaQueryWrapper<SysTimers>().eq(SysTimers::getJobParams, deviceBase.getId() + ""));
            if (CollectionUtils.isNotEmpty(timers)) {
                log.info("设备【{}】 已经存在定时任务！", deviceBase.getName());
                continue;
            }
            if (ObjectUtil.equal(deviceBase.getDeviceType(), "1") || ObjectUtil.equal(deviceBase.getDeviceType(), "7") || ObjectUtil.equal(deviceBase.getDeviceType(), "5")
                    || ObjectUtil.equal(deviceBase.getDeviceType(), "4") || ObjectUtil.equal(deviceBase.getDeviceType(), "10")) {
                SysTimers sysTimers = new SysTimers();
                sysTimers.setJobParams(deviceBase.getId() + "");
                sysTimers.setActionClass("vip.xiaonuo.tasks.IssuedTask");
                sysTimers.setCron("*/20 * * * * ?");
                sysTimers.setJobStatus(TimerJobStatusEnum.RUNNING.getCode());
                sysTimers.setTimerName("【 " + deviceBase.getName() + "】" + deviceBase.getId());
                sysTimers.setRemark("人员下发定时任务 每20s执行一次!");
                sysTimersService.save(sysTimers);
                deviceBase.setTaskId(sysTimers.getId());
                deviceBaseService.updateById(deviceBase);
                timerExeService.startTimer(sysTimers.getId().toString(), String.valueOf(sysTimers.getJobParams()), sysTimers.getCron(), sysTimers.getActionClass());
            }

            if (!TaskUtil.executeXxlJob() && ObjectUtil.equal(deviceBase.getDeviceType(), DeviceCategory.SUB_TYPE_PALM + "")) {
                // 新增设备定时任务 定时与掌静脉设备通信
                SysTimers sysTimers = new SysTimers();
                sysTimers.setJobParams(deviceBase.getId() + "");
                sysTimers.setActionClass("vip.xiaonuo.vein.task.PushDataToPalmVeinDeviceTimerTask");
                sysTimers.setCron("*/20 * * * * ?");
                sysTimers.setJobStatus(TimerJobStatusEnum.RUNNING.getCode());
                sysTimers.setTimerName("掌静脉特征值下发【 " + deviceBase.getName() + "】" + deviceBase.getId());
                sysTimers.setRemark("与掌静脉设备定时通信 每20s执行一次!");
                sysTimersService.save(sysTimers);
                deviceBase.setTaskId(sysTimers.getId());
                deviceBaseService.updateById(deviceBase);
                timerExeService.startTimer(sysTimers.getId().toString(), String.valueOf(sysTimers.getJobParams()), sysTimers.getCron(), sysTimers.getActionClass());
            }

        }
    }
}
